Skip to content

v26.48.0 release notes - #40113

Open
bosconi wants to merge 18 commits into
mainfrom
docs/v26.48.0-release-notes
Open

bosconi wants to merge 18 commits into
mainfrom
docs/v26.48.0-release-notes

Conversation

@bosconi

@bosconi bosconi commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Release notes for the v26.48.0 train. One commit is added per snapshot; the final snapshot sets the real dates. Applied: rc.1, rc.2, rc.3, final — the train is complete.

  • Content: 3 Feature sections (upsert hydration; Kafka sink headers GA; MySQL EXCLUDE ALL NOT NULL CONSTRAINTS), 9 Improvements, 2 Guides, 4 Bug Fixes. No Agent Skills section — every agent-skills PR in all four windows was omitted.
  • Scope: 123 PRs across the four snapshots — rc.1 114 (14 included), rc.2 5 (0 included), rc.3 1 (1 included), final 3 (0 included).
  • Dates — now real, not provisional: Cloud 2026-10-29, Self-Managed 2026-10-30. The rc.1-anchored provisional estimate was right, so final left both files unchanged. The v26.48.0 tag's commit date is 2026-10-28T18:35:05Z, a Wednesday; the first Thursday on or after it is 2026-10-29, with Self-Managed the day after.
  • Operator compatibility: row for v26.48, release date 2026-10-30. Unchanged by rc.2, rc.3, and final.
  • Branch base: main, whose newest published section was ## v26.46.1 when this branch was cut; v26.47.0 and v26.47.1 have since merged in. v26.48.0 stays at the top of the list.

final increment — empty, and verified empty

final's commit is empty. The tracking issue (release#627) lists exactly one item, the unassociated 4edd60a8d "release: bump to version v26.48.0", which the release-process-automation rule omits. The three agent-skills PRs in the window (#118, #119, #120) were all omitted.

This was verified rather than assumed, because a zero-PR snapshot and a failed fetch produce identical output: compare/v26.48.0-rc.3...v26.48.0 returns total_commits: 1, and that commit is the version bump. Nothing merged onto the release branch in the 42 h 49 m between the rc.3 tag and the ship tag. Across the train, every agent-skills PR from #111 to #120 falls in exactly one window, with no gaps or overlaps.

⚠️ One decision is still open for the release owner — see "Upsert v2" below. Every flag this train held open was re-read in source at the v26.48.0 ship tag rather than inherited from the RC snapshots:

Flag Default at v26.48.0 Source Held since Disposition
enable_upsert_v2 false src/storage-types/src/dyncfgs.rs:505-509 rc.2 ⚠️ premise contradicted — see below
enable_upsert_chunked_stash false src/storage-types/src/dyncfgs.rs:469-475 rc.2 same
enable_upsert_paged_spill false src/storage-types/src/dyncfgs.rs:450-455 rc.2 same
enable_mcp_protocol_2026_07_28 false src/adapter-dyncfgs/src/dyncfgs.rs:295-299 rc.1 hold stands — still omitted
cluster-details-page-cns-173 n/a (LaunchDarkly) no source default rc.1 hold stands — still omitted

The rc.2 hold on #40189 rests on a premise this branch now contradicts. rc.2 omitted it at Borderline on exactly one ground — every measurement is taken on a path enable_upsert_v2 keeps off by default — and asked whether any environment actually runs upsert v2. The branch answers that without anyone feeding the answer back: the human-added "Improved hydration times and memory efficiency for upsert sources" section states "This change has been rolled out to all Materialize Cloud environments and applies to all existing and new clusters." The three flags still read false at the ship tag, which is exactly the source-default-versus-LaunchDarkly divergence the rollout-lever rule covers: the published docs call wins, and the sole stated reason for the omit has fallen away.

  • Not already covered. The published section is about hydration — building a source from scratch, 206 min → 108–113 min, 542 GiB → 183–208 GiB. storage: make the chunked upsert v2 stash time-major #40189 is about catch-up after a backlog, a different operation with its own motivating incident (CPU-320: a source that "could not catch up on any replica size after a producer rate increase"). A customer who read the hydration section would learn nothing about catch-up.
  • Suggested Improvements bullet, to add only if you confirm — it was not applied in the final commit:

    Faster catch-up for upsert sources with a large backlog: An upsert source working through a backlog now drains one timestamp per round instead of merging and re-pushing the whole backlog each round, so catch-up time grows linearly rather than quadratically with the backlog; draining a 100-timestamp tail fell from 6.5 to 0.15 seconds, and a 400-timestamp tail drains in 0.67 seconds.

  • Caveat that must travel with the decision: the baseline in those timings is the paged flavor on main, not the configuration Cloud ran before this rollout — so they are not a clean before/after for a given customer. Dropping the two timings and keeping the linear-versus-quadratic claim holds regardless of baseline.
  • Two weaker links, stated rather than buried: that the rolled-out configuration is the one storage: make the chunked upsert v2 stash time-major #40189 was measured on is inferred from the published section's prose (its "buffer pool … serve sequential work from disk" reads as chunked stash plus paged spill), not confirmed by anyone. And the author declared "Release notes: None", naming enable_upsert_v2 — so publishing this would be an override of an author signal, justified by your own later rollout statement.
  • Third consecutive train to hold this flag: v26.44.0-rc.1 (#39041), v26.45.0-rc.1 (#39044), v26.48.0-rc.2 (storage: make the chunked upsert v2 stash time-major #40189). If the rollout statement is accurate, the earlier two are worth revisiting rather than left to age out.

The other two holds stand, corroborated. enable_mcp_protocol_2026_07_28 still reads false at the ship tag and the five MCP PRs rc.1 held appear nowhere in the section; neither does the Console cluster-details page stack. In both cases you had the whole train in view and did not promote them — the confirmation rc.1 asked for, arriving in the negative.

No duplicates, re-checked at ship. The seven PRs rc.1 flagged as already covered by v26.47.0 are still absent, the ## v26.47.1 section is untouched, and rc.3's entry (#40065) appears exactly once.

Two notes on human edits to this branch, both recorded as fact rather than objection:

  • 524adb8 removed the rc.1 feature section "Native Google Cloud Storage for persist" (#39983) outright. Flagging it only because a published entry disappearing is easy to miss in a long branch — if that was deliberate, nothing to do.
  • Two rc.1 Improvements were promoted to their own feature sections with docs links and a code sample (Kafka sink headers #39908; MySQL EXCLUDE ALL NOT NULL CONSTRAINTS #39873), and a Guides section was added that is not in the skill's template. The lesson for next time: an option whose flag flipped to true in the same release more likely warrants a feature section than the Improvements bullet the rubric suggests by default.

Carried forward from rc.3 and still open: the K8s recovery: envd on failing node nightly — the job that sank #40029, the first attempt at what #40065 re-lands — was not checked; it needs Buildkite, outside this run. The entry itself was verified correct in source at both the rc.3 and ship tags, so this is a CI-confidence question, not a notes-accuracy one.

rc.3 increment

One Improvement, for #40065: a read-only environmentd that reboots to pick up DDL changes during zero-downtime upgrade catch-up now restarts in place rather than exiting its container, so Kubernetes no longer applies crash-restart backoff. Not inherited from rc.1 — rc.1 correctly omitted the first attempt (#40029) together with its revert (#40061) as a no-op on main; rc.3 re-lands the behavior in narrowed form, verified as a real change by comparing entrypoint.sh at the v26.47.0 tag (no retry loop) against v26.48.0-rc.3 (re-exec on exit 75). The draft's closing "so zero-downtime upgrades catch up faster" was cut: no cited PR measures an upgrade duration, so the entry claims only the mechanism.

  • Not a Bug Fix. 0dt upgrades completed on v26.47.0; the catch-up reboots merely collected backoff delay. Existing behavior improved, so Improvements.
  • Residual, deliberately unpublished. A stale read-only process in a replaced pod still restarts in place on these halts until the kubelet kills its container, competing with its replacement for the generation's replicas. The MZ_RESTARTED_IN_PLACE marker check keeps it from booting writable, so it cannot fence the leader — the failure Revert "environmentd: restart halts within the container (#40029)" #40061 reverted. Worth watching if 0dt reports look odd after this ships.

rc.2 increment — empty, by design

rc.2's commit is empty: no entry was published and the provisional dates did not move. It exists so later runs can see from the commit subject that rc.2 was applied. Its single materialize PR, #40189, is the open item discussed under the final increment above.

rc.1 — standing warnings

⚠️ Seven PRs in rc.1's tracking issue were already covered by the v26.47.0 train, and none is republished here. v26.47.0 took five RCs whose later ones were cherry-picks onto the release branch; the same PRs appear in this issue because they are also what landed on main for v26.48.0. Four of the seven shipped to Cloud in v26.47.0 on 2026-10-22 — #37653, #39910, #39927, #40036 — so republishing any of them would put duplicate text in front of customers eight days later. The other three (#39903, #39906, #40046) were held at Borderline in v26.47.0 and are held again here, each reason re-checked rather than inherited. The "snapshots are disjoint by construction" guarantee holds within a train, not across trains, so this was caught mechanically by grepping every PR number in the issue against the v26.47.0 snapshot directories. All seven are listed under their own heading in rc.1/omitted.md.

Open questions for the release owner

Resolved since rc.1: the Kafka sink headers framing question — the GA section on this branch answers it.

Verification notes — rc.1's Step 5 pass cut one drafted entry and rewrote four:

  • Cut: a Bug Fix drafted for persist: halt with exit code 168 when a live reader loses its lease #40032 ("halt with exit code 168 when a live reader loses its lease"). The PR's own Problem section is about alerting — mz_persist_lease_timeout_read cannot distinguish a dead reader from a stuck one — and the follow-up it names is a Cloud alerting change. Nothing a customer observes changes.
  • tzdata (sql: bump chrono-tz fork to tzdata 2026e #40045): the draft said the Canadian zones move to "permanent daylight saving time", the author's prose. The PR's data table shows a permanent −05/EST and −06/CST — summer offsets kept year-round, but with another zone's standard-time abbreviations, which is what a user sees from AT TIME ZONE. Reworded to what the table supports.
  • Hydration memory (compute: bound the heap of correction V2's many-stale-times consolidation #39923): scoped to the consolidation step and the measured outcome (~628 GiB peak, no restart, against every pre-change run exiting on the 849 GiB limit). The PR explicitly says the fix "covers this consolidation path, not the sink's whole footprint"; CPU-317 tracks the rest.
  • Kafka clients (storage: create Kafka reader consumers only on workers that own partitions #40026): "55 to 24" is measured on a 4-worker, 11-source setup. The CPU throttling and degraded freshness are observed symptoms of the old behavior at a few hundred sources, not a measured post-change result at that scale, so the entry states the count as the outcome and the throttling as what the count drove.
  • environmentd accept backlog (server-core: Raise the listen backlog to 1024 #40035): the author's hedge is kept — "less likely to be restarted", not eliminated, because the PR says "This makes the queue fill later, not never."

Judgment calls a reviewer may want to revisit — #39605 is filed as an Improvement, not a Bug Fix: nothing was incorrect, an unbounded operation gained a bound and a knob. #40101 is filed as a Bug Fix rather than omitted under the internal-logging rule, because credentials reaching the logs is a security defect with a user-visible remedy; only credentials a user inlined rather than wrapped in a SECRET were affected.

Snapshot drafts (with PR links) in mz-skills:

Borderline PRs omitted: rc.1: 12 — omitted.md#borderline, rc.2: 1 — omitted.md#borderline, rc.3: 0, final: 0

🤖 Generated with Claude Code

@bosconi
bosconi requested a review from a team as a code owner October 23, 2026 07:17
- **External autoscaling for the connection balancer**: The `Materialize` resource gains a `balancerdExternallyScaled` field, and `Balancer` an `externallyScaled` field, that stop the Kubernetes operator from reasserting the balancerd Deployment's replica count on every reconcile, so a HorizontalPodAutoscaler can own it; `balancerdReplicas` then only seeds the count when the Deployment is first created.

### Guides {#v26.48-guides}
- [Transactional downstream updates using Kafka](/export-data/patterns/transactional-downstream-updates-kafka/)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links to the pattern page from #40120, which should merge this week. If #40113 merges first, this link 404s until then.

@val-materialize

Copy link
Copy Markdown
Contributor

Pushed two commits to this branch for the Kafka sink headers GA:

  • Merged main into the branch. The branch was behind main, so its base had no v26.47.0 or v26.47.1 entries. The release notes now keep v26.47.1 and v26.47.0 below v26.48.0, and the self-managed operator compatibility table keeps the v26.47.1 and v26.47 rows below v26.48. No history was rewritten.
  • doc: v26.48.0 release notes: Kafka sink headers GA
    • Removed the "Kafka sink headers on by default" bullet from Improvements.
    • Added a "Kafka sink headers are generally available" section after "Native Google Cloud Storage for persist". It covers the HEADERS option and the materialize-sink-id header, both GA in v26.48 now that SS-517 - Enable Kafka sink headers feature and sink-id header by default #39908 turns their flags on by default. It links to CREATE SINK: Headers and to the new pattern page.
    • Added a ### Guides section before Bug Fixes with the pattern page.

Related:

🤖 Generated with Claude Code

maheshwarip added a commit that referenced this pull request Oct 28, 2026
### Motivation

Adds the upsert source hydration improvement to the v26.48.0 release
notes. This PR targets the release notes branch of
#40113, not `main`.

### Description

- New feature section, **Improved hydration times and memory efficiency
for upsert sources** (`{#v26.48-upsert-hydration}`), placed first under
`## v26.48.0`.
- New chart
`doc/user/static/images/releases/v2648_upsert_hydration.png`, comparing
old and new hydration time and peak memory plus disk usage.
- Hydration time comes from the "Catch-up" row of the benchmark run
(206.1 min old vs 107.9–113.3 min new across four tested
configurations). The peak memory plus disk figures (542 GiB old vs
183–208 GiB new) were supplied separately.
- Links to the blog post:
https://materialize.com/blog/materialize-out-of-core/

### Verification

Checked the rendered chart image and the Markdown section by hand.

---
_Generated by [Claude
Code](https://claude.ai/code/session_016DcnmrsjsfSMzxGBGkmEuK)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
@maheshwarip
maheshwarip force-pushed the docs/v26.48.0-release-notes branch from d6d8443 to 68501f0 Compare October 28, 2026 18:50
maheshwarip added a commit that referenced this pull request Oct 28, 2026
### Motivation

Adds the upsert source hydration improvement to the v26.48.0 release
notes. This PR targets the release notes branch of
#40113, not `main`.

### Description

- New feature section, **Improved hydration times and memory efficiency
for upsert sources** (`{#v26.48-upsert-hydration}`), placed first under
`## v26.48.0`.
- New chart
`doc/user/static/images/releases/v2648_upsert_hydration.png`, comparing
old and new hydration time and peak memory plus disk usage.
- Hydration time comes from the "Catch-up" row of the benchmark run
(206.1 min old vs 107.9–113.3 min new across four tested
configurations). The peak memory plus disk figures (542 GiB old vs
183–208 GiB new) were supplied separately.
- Links to the blog post:
https://materialize.com/blog/materialize-out-of-core/

### Verification

Checked the rendered chart image and the Markdown section by hand.

---
_Generated by [Claude
Code](https://claude.ai/code/session_016DcnmrsjsfSMzxGBGkmEuK)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Comment thread doc/user/content/releases/_index.md
val-materialize added a commit that referenced this pull request Oct 29, 2026
…ader (#40120)

Adds a new **Export data > Patterns** section with one page,
**Transactional downstream updates using Kafka**. The page shows how a
consumer loading a Kafka sink into another store (Snowflake example) can
expose only timestamps the sink has fully committed, by gating on the
sink's progress frontier and joining data and progress records via the
`materialize-sink-id` header.

### Where each fact comes from

| Fact | Source |
|------|--------|
| Every message carries `materialize-timestamp` (value is the timestamp
as a decimal string) | `src/storage/src/sink/kafka.rs`
(`KafkaTxProducer::send`, `time.to_string()`) |
| `materialize-sink-id` header value is the sink's `GlobalId` (for
example `u123`), emitted when `kafka_sink_emit_sink_id_header` is on |
`src/storage/src/sink/kafka.rs` (`sink_id_header: ...
sink_id.to_string()`); `src/storage-types/src/dyncfgs.rs` |
| Progress record key is `mz-sink-{sink_id}` |
`src/storage-client/src/sink.rs` (`ProgressKey::new`) |
| Progress record value is JSON `{"frontier":[<ts>],"version":<n>}`;
`frontier` is the exclusive upper of committed times |
`src/storage/src/sink/kafka.rs` (`ProgressRecord`, `serialize_frontier`,
`commit_transaction`, `progress_record_migration` test) |
| Progress record is written in the same Kafka transaction as the data |
`src/storage/src/sink/kafka.rs` (`commit_transaction`) |
| A transaction and progress record are committed on every frontier
advance, even with no data | `src/storage/src/sink/kafka.rs` (sink loop,
`Event::Progress` branch) |
| Default progress topic name
`_materialize-progress-{env}-{connection}`, shared by all sinks on a
connection; name exposed in `mz_kafka_connections.sink_progress_topic` |
`src/storage-types/src/connections.rs` (`progress_topic`);
`doc/user/content/sql/create-sink/kafka.md`;
`doc/user/content/sql/system-catalog/mz_catalog.md` |
| Consumers need `isolation.level=read_committed`; exactly-once details
| `doc/user/content/sql/create-sink/kafka.md` (Exactly-once processing)
|
| `materialize-` header prefix is reserved |
`src/storage/src/sink/kafka.rs`;
`doc/user/content/sql/create-sink/kafka.md` |
| Snowflake connector stores payload in `RECORD_CONTENT`, headers in
`RECORD_METADATA:headers`, and the key in `RECORD_METADATA:key` only
with `StringConverter` | [Snowflake Kafka connector
overview](https://docs.snowflake.com/en/user-guide/kafka-connector-overview)
|

### Notes for reviewers

- **GA status:** the `materialize-sink-id` header and the `HEADERS`
option are GA in v26.48 (#39908 turns both flags on by default), so the
page has no private preview caveat. The Kafka sink docs drop their
preview callouts in #39829, and the v26.48.0 release notes (#40113) link
to this page.
- The Snowflake SQL is marked illustrative. The page names no connector
settings except `key.converter`, which the Snowflake docs confirm.

Part of [SS-504](https://linear.app/materializeinc/issue/SS-504).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
claude and others added 16 commits October 29, 2026 16:38
Adds the v26.48.0 section to doc/user/content/releases/_index.md and the
v26.48 row to the self-managed operator compatibility table.

Dates are provisional (Cloud 2026-10-29, Self-Managed 2026-10-30) and are
set for real by the final snapshot.

Draft with PR links:
https://github.com/MaterializeInc/mz-skills/blob/main/data/mz-release-notes/v26.48.0/rc.1/release_notes.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No published increment: the rc.2 snapshot covered one materialize PR
(upsert v2 drain performance), held at Borderline because it only runs
behind the enable_upsert_v2 dyncfg, which defaults to false at the
v26.48.0-rc.2 tag. The four agent-skills PRs in the window were
automated docs syncs and were omitted.

Provisional dates are unchanged from rc.1 (Cloud 2026-10-29,
Self-Managed 2026-10-30), so neither _index.md nor the operator
compatibility table changes. This empty commit records that rc.2 was
applied so later runs do not re-sweep it.
Adds the rc.3 increment: one Improvements entry for #40065, which makes
a read-only environmentd restart in place rather than exit its container
when it reboots to pick up DDL changes during zero-downtime upgrade
catch-up, so Kubernetes no longer applies crash-restart backoff.

Provisional dates are unchanged from rc.1 and rc.2 (Cloud 2026-10-29,
Self-Managed 2026-10-30), so the operator compatibility table is
untouched.
### Motivation

Adds the upsert source hydration improvement to the v26.48.0 release
notes. This PR targets the release notes branch of
#40113, not `main`.

### Description

- New feature section, **Improved hydration times and memory efficiency
for upsert sources** (`{#v26.48-upsert-hydration}`), placed first under
`## v26.48.0`.
- New chart
`doc/user/static/images/releases/v2648_upsert_hydration.png`, comparing
old and new hydration time and peak memory plus disk usage.
- Hydration time comes from the "Catch-up" row of the benchmark run
(206.1 min old vs 107.9–113.3 min new across four tested
configurations). The peak memory plus disk figures (542 GiB old vs
183–208 GiB new) were supplied separately.
- Links to the blog post:
https://materialize.com/blog/materialize-out-of-core/

### Verification

Checked the rendered chart image and the Markdown section by hand.

---
_Generated by [Claude
Code](https://claude.ai/code/session_016DcnmrsjsfSMzxGBGkmEuK)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Drop the GCS persist note, note the new cluster details page on
Self-Managed, and list the sub-second freshness and Iceberg sink
troubleshooting guides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match the v26.47 PostgreSQL section and link the MySQL docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The final snapshot adds no entries: the v26.48.0 tracking issue lists only
the version bump commit, and comparing v26.48.0-rc.3...v26.48.0 confirms a
single commit on the release branch. The three agent-skills PRs in the
window were all omitted.

The provisional dates carried since rc.1 (Cloud 2026-10-29, Self-Managed
2026-10-30) match the real ship dates, so the date refresh in
_index.md and self_managed_operator_compatibility.yml is a no-op.

This commit is empty; it records on the branch that the final snapshot has
been applied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maheshwarip
maheshwarip requested review from a team as code owners October 29, 2026 20:51
@maheshwarip
maheshwarip requested review from a team as code owners October 29, 2026 20:51
@maheshwarip
maheshwarip requested a review from jdonelson October 29, 2026 20:51
@maheshwarip

Copy link
Copy Markdown
Contributor

https://ohshitgit.com/ 🤦🏾

I'll fix this

@maheshwarip
maheshwarip changed the base branch from main to pm-metrics-draft October 29, 2026 20:56
@maheshwarip
maheshwarip requested review from a team, DAlperin and SangJunBak as code owners October 29, 2026 20:56
@maheshwarip
maheshwarip changed the base branch from pm-metrics-draft to main October 29, 2026 20:56
@maheshwarip

Copy link
Copy Markdown
Contributor

ok fixed - sorry for the review inbox spam team

@maheshwarip
maheshwarip force-pushed the docs/v26.48.0-release-notes branch from 2c2ac00 to 0061014 Compare October 29, 2026 20:57
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also expand the Self-Managed cluster details page note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants